Natalie Adams and Matthew Haraden
Story Memo Link: https://docs.google.com/document/d/1FNg8osWoG5mVxaWA0KETqtRD_43NwM_R2noyWTJPKB4/edit?usp=sharing
For our final project, we plan to focus on the prevalence of grocery
stores in Baltimore City. Food deserts are an issue in cities,
especially in low income and minority areas.
Looking into grocery store data in Baltimore can help us determine if
these stores are more accessible to people of a higher income versus
people of a lower income. It can also help us see if there are any
particular grocery stores that appear more often in higher income
communities. The same goes for majority white and non-white majority
neighborhoods. This data can be used to find possible discrepancies for
grocery store locations in Baltimore.
Questions: How many grocery stores are in low income neighborhoods?
How many grocery stores are in high income neighborhoods? How many
grocery stores are in majority non-white neighborhoods? How many grocery
stores are in majority white neighborhoods? How does this compare to
convenience stores?
Things to Consider: How to define high and low income How to define
majority white and non-majority white
Grocery Datasets: Supermarkets, Small Grocery Stores and Convenience
Stores in Maryland https://data-clf.hub.arcgis.com/datasets/cce1f648db4b41acafdd66e45d8ad529_595/explore?location=38.803090%2C-77.248650%2C8.00&showTable=true
Income Datasets: https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::median-household-income-community-statistical-area/explore?location=39.284832%2C-76.620524%2C12.52&showTable=true
Race Datasets: https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::total-population/explore?layer=0&location=39.284832%2C-76.620524%2C12.52&showTable=true
https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::percent-of-residents-white-caucasian-non-hispanic-community-statistical-area-1/explore?location=39.284832%2C-76.620524%2C12.52
https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::percent-of-residents-black-african-american-non-hispanic-community-statistical-area/explore?location=39.284832%2C-76.620524%2C12.52
https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::percent-of-residents-hispanic-community-statistical-area-1/explore?location=39.284832%2C-76.620524%2C12.52
https://vital-signs-bniajfi.hub.arcgis.com/datasets/percent-of-residents-asian-non-hispanic-community-statistical-area-1/explore?location=39.284832%2C-76.620524%2C12.52&showTable=true
https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::percent-of-residents-all-other-races-hawaiian-pacific-islander-alaskan-native-american-other-race-non-hispanic-community-statistical-area-1/explore?location=39.284832%2C-76.620524%2C12.52
https://vital-signs-bniajfi.hub.arcgis.com/datasets/bniajfi::percent-of-residents-two-or-more-races-non-hispanic-community-statistical-area-1/explore?location=39.284832%2C-76.620524%2C12.52
#load libraries
# turn off scientific notation
options(scipen=999)
# load libraries
library(janitor)
Attaching package: ‘janitor’
The following objects are masked from ‘package:stats’:
chisq.test, fisher.test
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ─────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.3.6 ✔ purrr 0.3.4
✔ tibble 3.1.8 ✔ dplyr 1.0.10
✔ tidyr 1.2.1 ✔ stringr 1.4.1
✔ readr 2.1.2 ✔ forcats 0.5.2 ── Conflicts ────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
library(sf)
Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 8.2.1; sf_use_s2() is TRUE
library(leaflet)
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
library(magrittr)
Attaching package: ‘magrittr’
The following object is masked from ‘package:purrr’:
set_names
The following object is masked from ‘package:tidyr’:
extract
library(ggplot2)
#load data Grocery store data comes from the Johns Hopkins Center for
a Livable Future Open Data Portal and median household income and race
data comes from the Baltimore Neighborhood Indicators Alliance Vital
Signs Open Data Portal (see links above).
# food stores in maryland
stores <- read.csv("food_stores.csv")
# median household income by baltimore neighborhood
income <- read.csv("median_household_income.csv")
# baltimore neighborhoods shapefile
neighborhoods <- st_read("income_shapefiles/median_household_income.shp")
Reading layer `median_household_income' from data source
`/Users/natalieadams/Desktop/Jour472_Fall_2022/Final_Project/income_shapefiles/median_household_income.shp'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1393927 ymin: 557733.6 xmax: 1445503 ymax: 621406.8
Projected CRS: NAD83 / Maryland (ftUS)
# total population by baltimore neighborhood
total_pop1 <- read.csv("total_population.csv")
# white population by baltimore neighborhood
percent_white1 <- read.csv("percent_white.csv")
# black population by baltimore neighborhood
percent_black1 <- read.csv("percent_black.csv")
# hispanic population by baltimore neighborhood
percent_hispanic1 <- read.csv("percent_hispanic.csv")
# asian population by baltimore neighborhood
percent_asian1 <- read.csv("percent_asian.csv")
# other race population by baltimore neighborhood
percent_other1 <- read.csv("percent_other.csv")
# two or more races population by baltimore neighborhood
percent_more1 <- read.csv("percent_two_or_more.csv")
#baltimore population shapefile
population <- st_read("population_shapefiles/total_population.shp")
Reading layer `total_population' from data source
`/Users/natalieadams/Desktop/Jour472_Fall_2022/Final_Project/population_shapefiles/total_population.shp'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1393927 ymin: 557733.6 xmax: 1445503 ymax: 621406.8
Projected CRS: NAD83 / Maryland (ftUS)
#clean race data Cleaned the data to select just the neighborhood and
2020 population and then joined all the races together into one table.
We did this because we couldn’t locate a single dataframe organized by
race and neighborhood, so we combined separate ones and checked to make
sure the percentages added up to 100.
# total population by baltimore neighborhood clean
total_pop2 <- total_pop1 %>%
select(CSA2010, tpop20) %>%
clean_names() %>%
rename(neighborhood = 1, total_pop_2020 = 2)
# white population by baltimore neighborhood clean
percent_white2 <- percent_white1 %>%
select(CSA2010, pwhite20) %>%
clean_names() %>%
rename(neighborhood = 1, percent_white = 2)
# black population by baltimore neighborhood clean
percent_black2 <- percent_black1 %>%
select(CSA2010, paa20) %>%
clean_names() %>%
rename(neighborhood = 1, percent_black = 2)
# hispanic population by baltimore neighborhood clean
percent_hispanic2 <- percent_hispanic1 %>%
select(CSA2010, phisp20) %>%
clean_names() %>%
rename(neighborhood = 1, percent_hispanic = 2)
# asian population by baltimore neighborhood clean
percent_asian2 <- percent_asian1 %>%
select(CSA2010, pasi20) %>%
clean_names() %>%
rename(neighborhood = 1, percent_asian = 2)
# other race population by baltimore neighborhood clean
percent_other2 <- percent_other1 %>%
select(CSA2010, ppac20) %>%
clean_names() %>%
rename(neighborhood = 1, percent_other = 2)
# two or more races population by baltimore neighborhood clean
percent_more2 <- percent_more1 %>%
select(CSA2010, p2more20) %>%
clean_names() %>%
rename(neighborhood = 1, percent_two_or_more = 2)
# total baltimore population by race and baltimore neighborhood clean
baltimore_population <- total_pop2 %>%
inner_join(percent_white2, by="neighborhood") %>%
inner_join(percent_black2, by="neighborhood") %>%
inner_join(percent_hispanic2, by="neighborhood") %>%
inner_join(percent_asian2, by="neighborhood") %>%
inner_join(percent_other2, by="neighborhood") %>%
inner_join(percent_more2, by="neighborhood")
#clean grocery store data Selected relevant data points, filtered it
for just the Baltimore City stores and cleaned column names. Made
separate dataframes for supermarkets, small grocery stores and
convenience stores.
# baltimore stores
baltimore_stores <- stores %>%
select(Main_Categ, Company_Na, County, Address, ZIP_Code, X, Y) %>%
filter(County == "Baltimore City") %>%
clean_names() %>%
rename(store_type = 1, name = 2) %>%
st_as_sf(coords = c("x", "y"), crs = 4269) %>%
filter(store_type != "Public Market")
# baltimore supermarkets
supermarkets <- read_csv("food_stores.csv") %>%
select(Main_Categ, Company_Na, County, Address, ZIP_Code, X, Y) %>%
filter(County == "Baltimore City") %>%
clean_names() %>%
rename(store_type = 1, name = 2) %>%
filter(store_type == "Supermarket") %>%
st_as_sf(coords = c("x", "y"), crs = 4269)
Rows: 4690 Columns: 12── Column specification ────────────────────────────────────────────
Delimiter: ","
chr (8): Main_Categ, Sub_Catego, Company_Na, Address, City, Stat...
dbl (4): X, Y, OBJECTID, ZIP_Code
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# baltimore small grocery stores
small_grocery <- read_csv("food_stores.csv") %>%
select(Main_Categ, Company_Na, County, Address, ZIP_Code, X, Y) %>%
filter(County == "Baltimore City") %>%
clean_names() %>%
rename(store_type = 1, name = 2) %>%
filter(store_type == "Small Grocery/Corner Store") %>%
st_as_sf(coords = c("x", "y"), crs = 4269)
Rows: 4690 Columns: 12── Column specification ────────────────────────────────────────────
Delimiter: ","
chr (8): Main_Categ, Sub_Catego, Company_Na, Address, City, Stat...
dbl (4): X, Y, OBJECTID, ZIP_Code
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# baltimore convenience stores
convenience_stores <- read_csv("food_stores.csv") %>%
select(Main_Categ, Company_Na, County, Address, ZIP_Code, X, Y) %>%
filter(County == "Baltimore City") %>%
clean_names() %>%
rename(store_type = 1, name = 2) %>%
filter(store_type == "Convenience Store") %>%
st_as_sf(coords = c("x", "y"), crs = 4269)
Rows: 4690 Columns: 12── Column specification ────────────────────────────────────────────
Delimiter: ","
chr (8): Main_Categ, Sub_Catego, Company_Na, Address, City, Stat...
dbl (4): X, Y, OBJECTID, ZIP_Code
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#clean median household income data and neighborhoods shapefile
Selected most recent median household income data and cleaned column
names.
The median household income in Baltimore is $52,164, according to the
U.S. Census Bureau. This is less than the national median household
income of $65,000. We chose to use the Baltimore median household income
instead of the national median household income because it is more
representative of the city. We defined low income as a median household
income below Baltimore’s $52,164 median household income and high income
as above that number. There are 32 neighborhoods characterized as low
income and 23 neighborhoods characterized as high income.
# Load and clean low income neighborhood shapefile
low_income <- st_read("income_shapefiles/median_household_income.shp") %>%
clean_names() %>%
select(csa2010, mhhi20, geometry) %>%
rename(neighborhood = 1, median_income=2) %>%
mutate(
income_level = case_when(
median_income < 52164 ~ "low",
median_income >= 52164 ~ "high"
)
) %>%
filter(income_level == "low") %>%
st_transform(crs=4269)
Reading layer `median_household_income' from data source
`/Users/natalieadams/Desktop/Jour472_Fall_2022/Final_Project/income_shapefiles/median_household_income.shp'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1393927 ymin: 557733.6 xmax: 1445503 ymax: 621406.8
Projected CRS: NAD83 / Maryland (ftUS)
# Load and clean high income neighborhood shapefile
high_income <- st_read("income_shapefiles/median_household_income.shp") %>%
clean_names() %>%
select(csa2010, mhhi20, geometry) %>%
rename(neighborhood = 1, median_income=2) %>%
mutate(
income_level = case_when(
median_income < 52164 ~ "low",
median_income >= 52164 ~ "high"
)
) %>%
filter(income_level == "high") %>%
st_transform(crs=4269)
Reading layer `median_household_income' from data source
`/Users/natalieadams/Desktop/Jour472_Fall_2022/Final_Project/income_shapefiles/median_household_income.shp'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1393927 ymin: 557733.6 xmax: 1445503 ymax: 621406.8
Projected CRS: NAD83 / Maryland (ftUS)
# table for leaflet
baltimore_neighborhoods_income <- neighborhoods %>%
clean_names() %>%
select(csa2010, mhhi20) %>%
rename(neighborhood = 1, median_income=2) %>%
mutate(
income_level = case_when(
median_income < 52164 ~ "low",
median_income >= 52164 ~ "high"
)
)
#How does the number of supermarkets compare in low income and high
income Baltimore neighborhoods? There are 25 supermarkets in low income
neighborhoods and 24 supermarkets in high income neighborhoods. While
low income neighborhoods have one more supermarket than high income
neighborhoods, there are more low income neighborhoods (32) than high
income neighborhoods (23), making the ratio of supermarkets to
neighborhoods greater for high income neighborhoods. There are some low
income neighborhoods without a supermarket at all, while there are
enough supermarkets for every high income neighborhood, plus an
additional one. This shows that high income residents have greater
access to supermarkets and fresh food than low income residents.
# sort coordinates into low income neighborhoods
low_income_supermarkets <- supermarkets %>%
st_join(low_income) %>%
filter(income_level == "low")
# sort coordinates into high income neighborhoods
high_income_supermarkets <- supermarkets %>%
st_join(high_income) %>%
filter(income_level == "high")
#plot supermarkets in baltimore based on income
ggplot()+
geom_sf(data=neighborhoods)+
geom_sf(data=low_income_supermarkets %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=income_level))+
geom_sf(data=high_income_supermarkets %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=income_level))+
theme_minimal()+
labs(title = "Supermarkets in High and Low Income Baltimore Neighborhoods",
subtitle = "Johns Hopkins and Baltimore Neighborhood Indicators Alliance Data, 2022",
caption = "Graphic by Natalie Adams")

#How does the number of small grocery and corner stores compare in
low income and high income Baltimore neighborhoods? There are 289 small
grocery/corner stores in low income neighborhoods and 115 small
grocery/corner stores in high income neighborhoods. Low income
neighborhoods have more than twice as many small grocery/corner stores
than high income neighborhoods and have a greater ratio of small
grocery/corner stores than high income neighborhoods. Small
grocery/corner stores typically offer ethnic or cultural food options,
such as Asian or South American. The prevalence of small grocery/corner
stores in low income neighborhoods indicates a possible high non-white
population in those neighborhoods. Small grocery/corner stores could
also make up for the absence of access to supermarkets in these
communities, although access to fresh food could still be limited.
# sort coordinates into low income neighborhoods
low_income_small_grocery <- small_grocery %>%
st_join(low_income) %>%
filter(income_level == "low")
# sort coordinates into high income neighborhoods
high_income_small_grocery <- small_grocery %>%
st_join(high_income) %>%
filter(income_level == "high")
#plot small grocery stores in baltimore based on income
ggplot()+
geom_sf(data=neighborhoods)+
geom_sf(data=low_income_small_grocery %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=income_level))+
geom_sf(data=high_income_small_grocery %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=income_level))+
theme_minimal()+
labs(title = "Small Grocery and Corner Stores in High and Low Income Baltimore Neighborhoods",
subtitle = "Johns Hopkins and Baltimore Neighborhood Indicators Alliance Data, 2022",
caption = "Graphic by Natalie Adams")

#How does the number of convenience stores compare in low income and
high income Baltimore neighborhoods? There are 166 convenience stores in
low income neighborhoods and 116 convenience stores in high income
neighborhoods. The average number of convenience stores in low and high
income neighborhoods is virtually the same (5.1 in low income compared
to 5.0 in high income). Convenience stores typically have “junk food”
and snacks, like chips, soda and candy. Large chain convenience stores,
such as Royal Farms and Wawa, have options to order hot food, like fried
chicken and sandwiches. Some convenience stores have fresh fruit, such
as apples and bananas, but overall, do not offer great access to fresh
food. While there is an equal percentage of convenience stores in high
income and low income neighborhoods, the lower percentage of
supermarkets in low income neighborhoods could indicate a stronger
reliance on convenience stores for buying food.
# sort coordinates into low income neighborhoods
low_income_convenience_stores <- convenience_stores %>%
st_join(low_income) %>%
filter(income_level == "low")
# sort coordinates into high income neighborhoods
high_income_convenience_stores <- convenience_stores %>%
st_join(high_income) %>%
filter(income_level == "high")
#plot convenience stores in baltimore based on income
ggplot()+
geom_sf(data=neighborhoods)+
geom_sf(data=low_income_convenience_stores %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=income_level))+
geom_sf(data=high_income_convenience_stores %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=income_level))+
theme_minimal()+
labs(title = "Convenience Stores in High and Low Income Baltimore Neighborhoods",
subtitle = "Johns Hopkins and Baltimore Neighborhood Indicators Alliance Data, 2022",
caption = "Graphic by Natalie Adams")

#Income Leaflet Graph
pal <- colorFactor(
palette = c('red', 'darkgreen', 'black'),
domain = baltimore_stores$store_type)
pal2 <- colorFactor(
palette = c('#fbd009', '#199bd6'),
domain = baltimore_neighborhoods_income$income_level)
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data=low_income,
color = ("#199bd6"),
weight = 1.5,
smoothFactor = 0.2,
fillOpacity = 0.1,
label = low_income$neighborhood) %>%
addPolygons(data=high_income,
color = ("#fbd009"),
weight = 1.5,
smoothFactor = 0.2,
fillOpacity = 0.1,
label = high_income$neighborhood) %>%
addCircles(data=baltimore_stores,
weight = 2,
color = ~pal(store_type),
label= paste("Store Name:",baltimore_stores$name)) %>%
addLegend(
position = "bottomleft",
pal = pal,
values = baltimore_stores$store_type,
title = "Stores by Type", group="group_1") %>%
addLegend(
position = "bottomright",
pal = pal2,
values = baltimore_neighborhoods_income$income_level,
title = "Neighborhood Income", group="group_2") %>%
addLayersControl(overlayGroups = c("group_1","group_2"),
options = layersControlOptions(collapsed = FALSE))
Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'
#clean race data and neighborhoods shapefile Selected white data and
cleaned column names.
We defined majority white neighborhoods as neighborhoods with a
neighborhood with a 50% or grater white population and non majority
white neighborhoods as a neighborhood with a less than 50% white
population. There are 11 majority white neighborhoods and 44 non
majority white neighborhoods.
# filter for majority white neighborhoods
majority_white <- st_read("income_shapefiles/median_household_income.shp") %>%
clean_names() %>%
select(csa2010, geometry) %>%
rename(neighborhood = 1) %>%
inner_join(percent_white2, by="neighborhood") %>%
mutate(
population_status = case_when(
percent_white < 50 ~ "non_majority_white",
percent_white >= 50 ~ "majority_white"
)
) %>%
filter(population_status == "majority_white") %>%
st_transform(crs=4269)
Reading layer `median_household_income' from data source
`/Users/natalieadams/Desktop/Jour472_Fall_2022/Final_Project/income_shapefiles/median_household_income.shp'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1393927 ymin: 557733.6 xmax: 1445503 ymax: 621406.8
Projected CRS: NAD83 / Maryland (ftUS)
# filter for non majority white neighborhoods
non_majority_white <- st_read("income_shapefiles/median_household_income.shp") %>%
clean_names() %>%
select(csa2010, geometry) %>%
rename(neighborhood = 1) %>%
inner_join(percent_white2, by="neighborhood") %>%
mutate(
population_status = case_when(
percent_white < 50 ~ "non_majority_white",
percent_white >= 50 ~ "majority_white"
)
) %>%
filter(population_status == "non_majority_white") %>%
st_transform(crs=4269)
Reading layer `median_household_income' from data source
`/Users/natalieadams/Desktop/Jour472_Fall_2022/Final_Project/income_shapefiles/median_household_income.shp'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1393927 ymin: 557733.6 xmax: 1445503 ymax: 621406.8
Projected CRS: NAD83 / Maryland (ftUS)
# table for leaflet
baltimore_neighborhoods_race <- baltimore_population %>%
select(neighborhood, percent_white) %>%
mutate(
population_status = case_when(
percent_white < 50 ~ "non_majority_white",
percent_white >= 50 ~ "majority_white"
)
)
#How does the number of supermarkets compare in majority white and
non majority white Baltimore neighborhoods? There are 14 supermarkets in
majority white neighborhoods and 35 supermarkets in non majority white
neighborhoods. While non majority white neighborhoods have a higher
number of supermarkets the ratio of supermarkets for majority white
neighborhoods (14 supermarkets for 11 neighborhoods) is greater than the
ratio of supermarkets for non majority white neighborhoods (35
supermarkets for 44 neighborhoods). This indicates that white residents
have greater access to supermarkets and fresh food than non white
residents.
# sort coordinates into majority white neighborhoods
majority_white_supermarkets <- supermarkets %>%
st_join(majority_white) %>%
filter(population_status == "majority_white")
# sort coordinates into non majority white neighborhoods
non_majority_white_supermarkets <- supermarkets %>%
st_join(non_majority_white) %>%
filter(population_status == "non_majority_white")
#plot supermarkets in baltimore based on race
ggplot()+
geom_sf(data=neighborhoods)+
geom_sf(data=majority_white_supermarkets %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=population_status))+
geom_sf(data=non_majority_white_supermarkets %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=population_status))+
theme_minimal()+
labs(title = "Supermarkets in Majority White and Non Majority White Baltimore Neighborhoods",
subtitle = "Johns Hopkins and Baltimore Neighborhood Indicators Alliance Data, 2022",
caption = "Graphic by Natalie Adams")

#How does the number of small grocery and corner stores compare in
majority white and non majority white Baltimore neighborhoods? There are
12 times as many small grocery/corner stores in non majority white
neighborhoods (373) than majority white neighborhoods (31). Small
grocery/corner stores typically offer ethnic or cultural food options,
such as Asian or South American, so it makes sense for most of these
stores to be in majority non white communities. It is unclear from this
data whether the high number of small grocery/corner stores is due to
preference of the neighborhood populations, a lack of access to other
types of food stores (such as supermarkets), other factors or a
combination of factors.
# sort coordinates into majority white neighborhoods
majority_white_small_grocery <- small_grocery %>%
st_join(majority_white) %>%
filter(population_status == "majority_white")
# sort coordinates into non majority white neighborhoods
non_majority_white_small_grocery <- small_grocery %>%
st_join(non_majority_white) %>%
filter(population_status == "non_majority_white")
#plot small grocery stores in baltimore based on race
ggplot()+
geom_sf(data=neighborhoods)+
geom_sf(data=majority_white_small_grocery %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=population_status))+
geom_sf(data=non_majority_white_small_grocery %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=population_status))+
theme_minimal()+
labs(title = "Small Grocery and Corner Stores in Majority White and Non Majority White Baltimore Neighborhoods",
subtitle = "Johns Hopkins and Baltimore Neighborhood Indicators Alliance Data, 2022",
caption = "Graphic by Natalie Adams")

#How does the number of convenience stores compare in majority white
and non majority white Baltimore neighborhoods? There are 49 convenience
stores in majority white neighborhoods and 233 convenience stores in non
majority white neighborhoods. The percentage of convenience stores in
majority white and non majority white neighborhoods is nearly equal (4.5
in majority white compared to 5.3 in non majority white). Convenience
stores typically have “junk food” and snacks, like chips, soda and
candy. Large chain convenience stores, such as Royal Farms and Wawa,
have options to order hot food, like fried chicken and sandwiches. Some
convenience stores have fresh fruit, such as apples and bananas, but
overall, do not offer great access to fresh food. While there is a
nearly equal percentage of convenience stores in majority white and non
majority white neighborhoods, the lower percentage of supermarkets in
non majority white neighborhoods could indicate a stronger reliance on
convenience stores for buying food.
# sort coordinates into majority white neighborhoods
majority_white_convenience_stores <- convenience_stores %>%
st_join(majority_white) %>%
filter(population_status == "majority_white")
# sort coordinates into non majority white neighborhoods
non_majority_white_convenience_stores <- convenience_stores %>%
st_join(non_majority_white) %>%
filter(population_status == "non_majority_white")
#plot convenience stores in baltimore based on race
ggplot()+
geom_sf(data=neighborhoods)+
geom_sf(data=majority_white_convenience_stores %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=population_status))+
geom_sf(data=non_majority_white_convenience_stores %>% st_as_sf(coords = c("x", "y"), crs = 4326), mapping=aes(color=population_status))+
theme_minimal()+
labs(title = "Convenience Stores in Majority White and Non Majority White Baltimore Neighborhoods",
subtitle = "Johns Hopkins and Baltimore Neighborhood Indicators Alliance Data, 2022",
caption = "Graphic by Natalie Adams")

#leaflet race graph
pal1 <- colorFactor(
palette = c('red', 'darkgreen', 'black'),
domain = baltimore_stores$store_type)
pal2 <- colorFactor(
palette = c('#fbd009', '#199bd6'),
domain = baltimore_neighborhoods_race$population_status)
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data=majority_white,
color = ("#fbd009"),
weight = 1.5,
smoothFactor = 0.2,
fillOpacity = 0.1,
label = majority_white$neighborhood) %>%
addPolygons(data=non_majority_white,
color = ("#199bd6"),
weight = 1.5,
smoothFactor = 0.2,
fillOpacity = 0.1,
label = non_majority_white$neighborhood) %>%
addCircles(data=baltimore_stores,
weight = 2,
color = ~pal(store_type),
label= paste("Store Name:",baltimore_stores$name)) %>%
addLegend(
position = "bottomleft",
pal = pal1,
values = baltimore_stores$store_type,
title = "Stores by Type", group="group_1") %>%
addLegend(
position = "bottomright",
pal = pal2,
values = baltimore_neighborhoods_race$population_status,
title = "Neighborhood Race", group="group_2") %>%
addLayersControl(overlayGroups = c("group_1","group_2"),
options = layersControlOptions(collapsed = FALSE))
Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'
LS0tCnRpdGxlOiAiQmFsdGltb3JlX0Zvb2RfRGVzZXJ0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpOYXRhbGllIEFkYW1zIGFuZCBNYXR0aGV3IEhhcmFkZW4KClN0b3J5IE1lbW8gTGluazogaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vZG9jdW1lbnQvZC8xRk5nOG9zV29HNW1WeGFXQTBLRVRxdFJEXzQzTndNX1Iybm95V1RKUEtCNC9lZGl0P3VzcD1zaGFyaW5nCgpGb3Igb3VyIGZpbmFsIHByb2plY3QsIHdlIHBsYW4gdG8gZm9jdXMgb24gdGhlIHByZXZhbGVuY2Ugb2YgZ3JvY2VyeSBzdG9yZXMgaW4gQmFsdGltb3JlIENpdHkuIEZvb2QgZGVzZXJ0cyBhcmUgYW4gaXNzdWUgaW4gY2l0aWVzLCBlc3BlY2lhbGx5IGluIGxvdyBpbmNvbWUgYW5kIG1pbm9yaXR5IGFyZWFzLgoKTG9va2luZyBpbnRvIGdyb2Nlcnkgc3RvcmUgZGF0YSBpbiBCYWx0aW1vcmUgY2FuIGhlbHAgdXMgZGV0ZXJtaW5lIGlmIHRoZXNlIHN0b3JlcyBhcmUgbW9yZSBhY2Nlc3NpYmxlIHRvIHBlb3BsZSBvZiBhIGhpZ2hlciBpbmNvbWUgdmVyc3VzIHBlb3BsZSBvZiBhIGxvd2VyIGluY29tZS4gSXQgY2FuIGFsc28gaGVscCB1cyBzZWUgaWYgdGhlcmUgYXJlIGFueSBwYXJ0aWN1bGFyIGdyb2Nlcnkgc3RvcmVzIHRoYXQgYXBwZWFyIG1vcmUgb2Z0ZW4gaW4gaGlnaGVyIGluY29tZSBjb21tdW5pdGllcy4gVGhlIHNhbWUgZ29lcyBmb3IgbWFqb3JpdHkgd2hpdGUgYW5kIG5vbi13aGl0ZSBtYWpvcml0eSBuZWlnaGJvcmhvb2RzLiBUaGlzIGRhdGEgY2FuIGJlIHVzZWQgdG8gZmluZCBwb3NzaWJsZSBkaXNjcmVwYW5jaWVzIGZvciBncm9jZXJ5IHN0b3JlIGxvY2F0aW9ucyBpbiBCYWx0aW1vcmUuCgpRdWVzdGlvbnM6CkhvdyBtYW55IGdyb2Nlcnkgc3RvcmVzIGFyZSBpbiBsb3cgaW5jb21lIG5laWdoYm9yaG9vZHM/CkhvdyBtYW55IGdyb2Nlcnkgc3RvcmVzIGFyZSBpbiBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzPwpIb3cgbWFueSBncm9jZXJ5IHN0b3JlcyBhcmUgaW4gbWFqb3JpdHkgbm9uLXdoaXRlIG5laWdoYm9yaG9vZHM/CkhvdyBtYW55IGdyb2Nlcnkgc3RvcmVzIGFyZSBpbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzPwpIb3cgZG9lcyB0aGlzIGNvbXBhcmUgdG8gY29udmVuaWVuY2Ugc3RvcmVzPwoKVGhpbmdzIHRvIENvbnNpZGVyOgpIb3cgdG8gZGVmaW5lIGhpZ2ggYW5kIGxvdyBpbmNvbWUKSG93IHRvIGRlZmluZSBtYWpvcml0eSB3aGl0ZSBhbmQgbm9uLW1ham9yaXR5IHdoaXRlCgpHcm9jZXJ5IERhdGFzZXRzOiAKU3VwZXJtYXJrZXRzLCBTbWFsbCBHcm9jZXJ5IFN0b3JlcyBhbmQgQ29udmVuaWVuY2UgU3RvcmVzIGluIE1hcnlsYW5kCmh0dHBzOi8vZGF0YS1jbGYuaHViLmFyY2dpcy5jb20vZGF0YXNldHMvY2NlMWY2NDhkYjRiNDFhY2FmZGQ2NmU0NWQ4YWQ1MjlfNTk1L2V4cGxvcmU/bG9jYXRpb249MzguODAzMDkwJTJDLTc3LjI0ODY1MCUyQzguMDAmc2hvd1RhYmxlPXRydWUgCgpJbmNvbWUgRGF0YXNldHM6Cmh0dHBzOi8vdml0YWwtc2lnbnMtYm5pYWpmaS5odWIuYXJjZ2lzLmNvbS9kYXRhc2V0cy9ibmlhamZpOjptZWRpYW4taG91c2Vob2xkLWluY29tZS1jb21tdW5pdHktc3RhdGlzdGljYWwtYXJlYS9leHBsb3JlP2xvY2F0aW9uPTM5LjI4NDgzMiUyQy03Ni42MjA1MjQlMkMxMi41MiZzaG93VGFibGU9dHJ1ZQoKUmFjZSBEYXRhc2V0czoKaHR0cHM6Ly92aXRhbC1zaWducy1ibmlhamZpLmh1Yi5hcmNnaXMuY29tL2RhdGFzZXRzL2JuaWFqZmk6OnRvdGFsLXBvcHVsYXRpb24vZXhwbG9yZT9sYXllcj0wJmxvY2F0aW9uPTM5LjI4NDgzMiUyQy03Ni42MjA1MjQlMkMxMi41MiZzaG93VGFibGU9dHJ1ZQpodHRwczovL3ZpdGFsLXNpZ25zLWJuaWFqZmkuaHViLmFyY2dpcy5jb20vZGF0YXNldHMvYm5pYWpmaTo6cGVyY2VudC1vZi1yZXNpZGVudHMtd2hpdGUtY2F1Y2FzaWFuLW5vbi1oaXNwYW5pYy1jb21tdW5pdHktc3RhdGlzdGljYWwtYXJlYS0xL2V4cGxvcmU/bG9jYXRpb249MzkuMjg0ODMyJTJDLTc2LjYyMDUyNCUyQzEyLjUyCmh0dHBzOi8vdml0YWwtc2lnbnMtYm5pYWpmaS5odWIuYXJjZ2lzLmNvbS9kYXRhc2V0cy9ibmlhamZpOjpwZXJjZW50LW9mLXJlc2lkZW50cy1ibGFjay1hZnJpY2FuLWFtZXJpY2FuLW5vbi1oaXNwYW5pYy1jb21tdW5pdHktc3RhdGlzdGljYWwtYXJlYS9leHBsb3JlP2xvY2F0aW9uPTM5LjI4NDgzMiUyQy03Ni42MjA1MjQlMkMxMi41MgrigIvigItodHRwczovL3ZpdGFsLXNpZ25zLWJuaWFqZmkuaHViLmFyY2dpcy5jb20vZGF0YXNldHMvYm5pYWpmaTo6cGVyY2VudC1vZi1yZXNpZGVudHMtaGlzcGFuaWMtY29tbXVuaXR5LXN0YXRpc3RpY2FsLWFyZWEtMS9leHBsb3JlP2xvY2F0aW9uPTM5LjI4NDgzMiUyQy03Ni42MjA1MjQlMkMxMi41MgpodHRwczovL3ZpdGFsLXNpZ25zLWJuaWFqZmkuaHViLmFyY2dpcy5jb20vZGF0YXNldHMvcGVyY2VudC1vZi1yZXNpZGVudHMtYXNpYW4tbm9uLWhpc3BhbmljLWNvbW11bml0eS1zdGF0aXN0aWNhbC1hcmVhLTEvZXhwbG9yZT9sb2NhdGlvbj0zOS4yODQ4MzIlMkMtNzYuNjIwNTI0JTJDMTIuNTImc2hvd1RhYmxlPXRydWUKaHR0cHM6Ly92aXRhbC1zaWducy1ibmlhamZpLmh1Yi5hcmNnaXMuY29tL2RhdGFzZXRzL2JuaWFqZmk6OnBlcmNlbnQtb2YtcmVzaWRlbnRzLWFsbC1vdGhlci1yYWNlcy1oYXdhaWlhbi1wYWNpZmljLWlzbGFuZGVyLWFsYXNrYW4tbmF0aXZlLWFtZXJpY2FuLW90aGVyLXJhY2Utbm9uLWhpc3BhbmljLWNvbW11bml0eS1zdGF0aXN0aWNhbC1hcmVhLTEvZXhwbG9yZT9sb2NhdGlvbj0zOS4yODQ4MzIlMkMtNzYuNjIwNTI0JTJDMTIuNTIKaHR0cHM6Ly92aXRhbC1zaWducy1ibmlhamZpLmh1Yi5hcmNnaXMuY29tL2RhdGFzZXRzL2JuaWFqZmk6OnBlcmNlbnQtb2YtcmVzaWRlbnRzLXR3by1vci1tb3JlLXJhY2VzLW5vbi1oaXNwYW5pYy1jb21tdW5pdHktc3RhdGlzdGljYWwtYXJlYS0xL2V4cGxvcmU/bG9jYXRpb249MzkuMjg0ODMyJTJDLTc2LjYyMDUyNCUyQzEyLjUyCgojbG9hZCBsaWJyYXJpZXMKYGBge3J9CiMgdHVybiBvZmYgc2NpZW50aWZpYyBub3RhdGlvbgpvcHRpb25zKHNjaXBlbj05OTkpCiMgbG9hZCBsaWJyYXJpZXMKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzZikKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKI2xvYWQgZGF0YQpHcm9jZXJ5IHN0b3JlIGRhdGEgY29tZXMgZnJvbSB0aGUgSm9obnMgSG9wa2lucyBDZW50ZXIgZm9yIGEgTGl2YWJsZSBGdXR1cmUgT3BlbiBEYXRhIFBvcnRhbCBhbmQgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgYW5kIHJhY2UgZGF0YSBjb21lcyBmcm9tIHRoZSBCYWx0aW1vcmUgTmVpZ2hib3Job29kIEluZGljYXRvcnMgQWxsaWFuY2UgVml0YWwgU2lnbnMgT3BlbiBEYXRhIFBvcnRhbCAoc2VlIGxpbmtzIGFib3ZlKS4KCmBgYHtyfQojIGZvb2Qgc3RvcmVzIGluIG1hcnlsYW5kCnN0b3JlcyA8LSByZWFkLmNzdigiZm9vZF9zdG9yZXMuY3N2IikKIyBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBieSBiYWx0aW1vcmUgbmVpZ2hib3Job29kCmluY29tZSA8LSByZWFkLmNzdigibWVkaWFuX2hvdXNlaG9sZF9pbmNvbWUuY3N2IikKIyBiYWx0aW1vcmUgbmVpZ2hib3Job29kcyBzaGFwZWZpbGUKbmVpZ2hib3Job29kcyA8LSBzdF9yZWFkKCJpbmNvbWVfc2hhcGVmaWxlcy9tZWRpYW5faG91c2Vob2xkX2luY29tZS5zaHAiKQojIHRvdGFsIHBvcHVsYXRpb24gYnkgYmFsdGltb3JlIG5laWdoYm9yaG9vZAp0b3RhbF9wb3AxIDwtIHJlYWQuY3N2KCJ0b3RhbF9wb3B1bGF0aW9uLmNzdiIpCiMgd2hpdGUgcG9wdWxhdGlvbiBieSBiYWx0aW1vcmUgbmVpZ2hib3Job29kCnBlcmNlbnRfd2hpdGUxIDwtIHJlYWQuY3N2KCJwZXJjZW50X3doaXRlLmNzdiIpCiMgYmxhY2sgcG9wdWxhdGlvbiBieSBiYWx0aW1vcmUgbmVpZ2hib3Job29kCnBlcmNlbnRfYmxhY2sxIDwtIHJlYWQuY3N2KCJwZXJjZW50X2JsYWNrLmNzdiIpCiMgaGlzcGFuaWMgcG9wdWxhdGlvbiBieSBiYWx0aW1vcmUgbmVpZ2hib3Job29kCnBlcmNlbnRfaGlzcGFuaWMxIDwtIHJlYWQuY3N2KCJwZXJjZW50X2hpc3BhbmljLmNzdiIpCiMgYXNpYW4gcG9wdWxhdGlvbiBieSBiYWx0aW1vcmUgbmVpZ2hib3Job29kCnBlcmNlbnRfYXNpYW4xIDwtIHJlYWQuY3N2KCJwZXJjZW50X2FzaWFuLmNzdiIpCiMgb3RoZXIgcmFjZSBwb3B1bGF0aW9uIGJ5IGJhbHRpbW9yZSBuZWlnaGJvcmhvb2QKcGVyY2VudF9vdGhlcjEgPC0gcmVhZC5jc3YoInBlcmNlbnRfb3RoZXIuY3N2IikKIyB0d28gb3IgbW9yZSByYWNlcyBwb3B1bGF0aW9uIGJ5IGJhbHRpbW9yZSBuZWlnaGJvcmhvb2QKcGVyY2VudF9tb3JlMSA8LSByZWFkLmNzdigicGVyY2VudF90d29fb3JfbW9yZS5jc3YiKQojYmFsdGltb3JlIHBvcHVsYXRpb24gc2hhcGVmaWxlCnBvcHVsYXRpb24gPC0gc3RfcmVhZCgicG9wdWxhdGlvbl9zaGFwZWZpbGVzL3RvdGFsX3BvcHVsYXRpb24uc2hwIikKYGBgCgojY2xlYW4gcmFjZSBkYXRhCkNsZWFuZWQgdGhlIGRhdGEgdG8gc2VsZWN0IGp1c3QgdGhlIG5laWdoYm9yaG9vZCBhbmQgMjAyMCBwb3B1bGF0aW9uIGFuZCB0aGVuIGpvaW5lZCBhbGwgdGhlIHJhY2VzIHRvZ2V0aGVyIGludG8gb25lIHRhYmxlLiBXZSBkaWQgdGhpcyBiZWNhdXNlIHdlIGNvdWxkbid0IGxvY2F0ZSBhIHNpbmdsZSBkYXRhZnJhbWUgb3JnYW5pemVkIGJ5IHJhY2UgYW5kIG5laWdoYm9yaG9vZCwgc28gd2UgY29tYmluZWQgc2VwYXJhdGUgb25lcyBhbmQgY2hlY2tlZCB0byBtYWtlIHN1cmUgdGhlIHBlcmNlbnRhZ2VzIGFkZGVkIHVwIHRvIDEwMC4KCmBgYHtyfQojIHRvdGFsIHBvcHVsYXRpb24gYnkgYmFsdGltb3JlIG5laWdoYm9yaG9vZCBjbGVhbgp0b3RhbF9wb3AyIDwtIHRvdGFsX3BvcDEgJT4lIAogIHNlbGVjdChDU0EyMDEwLCB0cG9wMjApICU+JSAKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSAxLCB0b3RhbF9wb3BfMjAyMCA9IDIpCiMgd2hpdGUgcG9wdWxhdGlvbiBieSBiYWx0aW1vcmUgbmVpZ2hib3Job29kIGNsZWFuCnBlcmNlbnRfd2hpdGUyIDwtIHBlcmNlbnRfd2hpdGUxICU+JSAKICBzZWxlY3QoQ1NBMjAxMCwgcHdoaXRlMjApICU+JSAKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSAxLCBwZXJjZW50X3doaXRlID0gMikKIyBibGFjayBwb3B1bGF0aW9uIGJ5IGJhbHRpbW9yZSBuZWlnaGJvcmhvb2QgY2xlYW4KcGVyY2VudF9ibGFjazIgPC0gcGVyY2VudF9ibGFjazEgJT4lIAogIHNlbGVjdChDU0EyMDEwLCBwYWEyMCkgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lCiAgcmVuYW1lKG5laWdoYm9yaG9vZCA9IDEsIHBlcmNlbnRfYmxhY2sgPSAyKQojIGhpc3BhbmljIHBvcHVsYXRpb24gYnkgYmFsdGltb3JlIG5laWdoYm9yaG9vZCBjbGVhbgpwZXJjZW50X2hpc3BhbmljMiA8LSBwZXJjZW50X2hpc3BhbmljMSAlPiUgCiAgc2VsZWN0KENTQTIwMTAsIHBoaXNwMjApICU+JSAKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSAxLCBwZXJjZW50X2hpc3BhbmljID0gMikKIyBhc2lhbiBwb3B1bGF0aW9uIGJ5IGJhbHRpbW9yZSBuZWlnaGJvcmhvb2QgY2xlYW4KcGVyY2VudF9hc2lhbjIgPC0gcGVyY2VudF9hc2lhbjEgJT4lIAogIHNlbGVjdChDU0EyMDEwLCBwYXNpMjApICU+JSAKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSAxLCBwZXJjZW50X2FzaWFuID0gMikKIyBvdGhlciByYWNlIHBvcHVsYXRpb24gYnkgYmFsdGltb3JlIG5laWdoYm9yaG9vZCBjbGVhbgpwZXJjZW50X290aGVyMiA8LSBwZXJjZW50X290aGVyMSAlPiUgCiAgc2VsZWN0KENTQTIwMTAsIHBwYWMyMCkgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lCiAgcmVuYW1lKG5laWdoYm9yaG9vZCA9IDEsIHBlcmNlbnRfb3RoZXIgPSAyKQojIHR3byBvciBtb3JlIHJhY2VzIHBvcHVsYXRpb24gYnkgYmFsdGltb3JlIG5laWdoYm9yaG9vZCBjbGVhbgpwZXJjZW50X21vcmUyIDwtIHBlcmNlbnRfbW9yZTEgJT4lIAogIHNlbGVjdChDU0EyMDEwLCBwMm1vcmUyMCkgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lCiAgcmVuYW1lKG5laWdoYm9yaG9vZCA9IDEsIHBlcmNlbnRfdHdvX29yX21vcmUgPSAyKQojIHRvdGFsIGJhbHRpbW9yZSBwb3B1bGF0aW9uIGJ5IHJhY2UgYW5kIGJhbHRpbW9yZSBuZWlnaGJvcmhvb2QgY2xlYW4KYmFsdGltb3JlX3BvcHVsYXRpb24gPC0gdG90YWxfcG9wMiAlPiUgCiAgaW5uZXJfam9pbihwZXJjZW50X3doaXRlMiwgYnk9Im5laWdoYm9yaG9vZCIpICU+JSAKICBpbm5lcl9qb2luKHBlcmNlbnRfYmxhY2syLCBieT0ibmVpZ2hib3Job29kIikgJT4lIAogIGlubmVyX2pvaW4ocGVyY2VudF9oaXNwYW5pYzIsIGJ5PSJuZWlnaGJvcmhvb2QiKSAlPiUgCiAgaW5uZXJfam9pbihwZXJjZW50X2FzaWFuMiwgYnk9Im5laWdoYm9yaG9vZCIpICU+JSAKICBpbm5lcl9qb2luKHBlcmNlbnRfb3RoZXIyLCBieT0ibmVpZ2hib3Job29kIikgJT4lIAogIGlubmVyX2pvaW4ocGVyY2VudF9tb3JlMiwgYnk9Im5laWdoYm9yaG9vZCIpCmBgYAoKI2NsZWFuIGdyb2Nlcnkgc3RvcmUgZGF0YQpTZWxlY3RlZCByZWxldmFudCBkYXRhIHBvaW50cywgZmlsdGVyZWQgaXQgZm9yIGp1c3QgdGhlIEJhbHRpbW9yZSBDaXR5IHN0b3JlcyBhbmQgY2xlYW5lZCBjb2x1bW4gbmFtZXMuIE1hZGUgc2VwYXJhdGUgZGF0YWZyYW1lcyBmb3Igc3VwZXJtYXJrZXRzLCBzbWFsbCBncm9jZXJ5IHN0b3JlcyBhbmQgY29udmVuaWVuY2Ugc3RvcmVzLgoKYGBge3J9CiMgYmFsdGltb3JlIHN0b3JlcwpiYWx0aW1vcmVfc3RvcmVzIDwtIHN0b3JlcyAlPiUgCiAgc2VsZWN0KE1haW5fQ2F0ZWcsIENvbXBhbnlfTmEsIENvdW50eSwgQWRkcmVzcywgWklQX0NvZGUsIFgsIFkpICU+JSAKICBmaWx0ZXIoQ291bnR5ID09ICJCYWx0aW1vcmUgQ2l0eSIpICU+JSAKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShzdG9yZV90eXBlID0gMSwgbmFtZSA9IDIpICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSwgY3JzID0gNDI2OSkgJT4lIAogIGZpbHRlcihzdG9yZV90eXBlICE9ICJQdWJsaWMgTWFya2V0IikKIyBiYWx0aW1vcmUgc3VwZXJtYXJrZXRzCnN1cGVybWFya2V0cyA8LSByZWFkX2NzdigiZm9vZF9zdG9yZXMuY3N2IikgJT4lIAogIHNlbGVjdChNYWluX0NhdGVnLCBDb21wYW55X05hLCBDb3VudHksIEFkZHJlc3MsIFpJUF9Db2RlLCBYLCBZKSAlPiUgCiAgZmlsdGVyKENvdW50eSA9PSAiQmFsdGltb3JlIENpdHkiKSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUKICByZW5hbWUoc3RvcmVfdHlwZSA9IDEsIG5hbWUgPSAyKSAlPiUKICBmaWx0ZXIoc3RvcmVfdHlwZSA9PSAiU3VwZXJtYXJrZXQiKSAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQyNjkpCiMgYmFsdGltb3JlIHNtYWxsIGdyb2Nlcnkgc3RvcmVzCnNtYWxsX2dyb2NlcnkgPC0gcmVhZF9jc3YoImZvb2Rfc3RvcmVzLmNzdiIpICU+JSAKICBzZWxlY3QoTWFpbl9DYXRlZywgQ29tcGFueV9OYSwgQ291bnR5LCBBZGRyZXNzLCBaSVBfQ29kZSwgWCwgWSkgJT4lIAogIGZpbHRlcihDb3VudHkgPT0gIkJhbHRpbW9yZSBDaXR5IikgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lCiAgcmVuYW1lKHN0b3JlX3R5cGUgPSAxLCBuYW1lID0gMikgJT4lCiAgZmlsdGVyKHN0b3JlX3R5cGUgPT0gIlNtYWxsIEdyb2NlcnkvQ29ybmVyIFN0b3JlIikgJT4lIAogIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpLCBjcnMgPSA0MjY5KQojIGJhbHRpbW9yZSBjb252ZW5pZW5jZSBzdG9yZXMKY29udmVuaWVuY2Vfc3RvcmVzIDwtIHJlYWRfY3N2KCJmb29kX3N0b3Jlcy5jc3YiKSAlPiUgCiAgc2VsZWN0KE1haW5fQ2F0ZWcsIENvbXBhbnlfTmEsIENvdW50eSwgQWRkcmVzcywgWklQX0NvZGUsIFgsIFkpICU+JSAKICBmaWx0ZXIoQ291bnR5ID09ICJCYWx0aW1vcmUgQ2l0eSIpICU+JSAKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShzdG9yZV90eXBlID0gMSwgbmFtZSA9IDIpICU+JQogIGZpbHRlcihzdG9yZV90eXBlID09ICJDb252ZW5pZW5jZSBTdG9yZSIpICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSwgY3JzID0gNDI2OSkKYGBgCgojY2xlYW4gbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgZGF0YSBhbmQgbmVpZ2hib3Job29kcyBzaGFwZWZpbGUKU2VsZWN0ZWQgbW9zdCByZWNlbnQgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgZGF0YSBhbmQgY2xlYW5lZCBjb2x1bW4gbmFtZXMuCgpUaGUgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgaW4gQmFsdGltb3JlIGlzICQ1MiwxNjQsIGFjY29yZGluZyB0byB0aGUgVS5TLiBDZW5zdXMgQnVyZWF1LiBUaGlzIGlzIGxlc3MgdGhhbiB0aGUgbmF0aW9uYWwgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgb2YgJDY1LDAwMC4gV2UgY2hvc2UgdG8gdXNlIHRoZSBCYWx0aW1vcmUgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgaW5zdGVhZCBvZiB0aGUgbmF0aW9uYWwgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgYmVjYXVzZSBpdCBpcyBtb3JlIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBjaXR5LiBXZSBkZWZpbmVkIGxvdyBpbmNvbWUgYXMgYSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBiZWxvdyBCYWx0aW1vcmUncyAkNTIsMTY0IG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGFuZCBoaWdoIGluY29tZSBhcyBhYm92ZSB0aGF0IG51bWJlci4gVGhlcmUgYXJlIDMyIG5laWdoYm9yaG9vZHMgY2hhcmFjdGVyaXplZCBhcyBsb3cgaW5jb21lIGFuZCAyMyBuZWlnaGJvcmhvb2RzIGNoYXJhY3Rlcml6ZWQgYXMgaGlnaCBpbmNvbWUuCgpgYGB7cn0KIyBMb2FkIGFuZCBjbGVhbiBsb3cgaW5jb21lIG5laWdoYm9yaG9vZCBzaGFwZWZpbGUKbG93X2luY29tZSA8LSBzdF9yZWFkKCJpbmNvbWVfc2hhcGVmaWxlcy9tZWRpYW5faG91c2Vob2xkX2luY29tZS5zaHAiKSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUKICBzZWxlY3QoY3NhMjAxMCwgbWhoaTIwLCBnZW9tZXRyeSkgJT4lIAogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSAxLCBtZWRpYW5faW5jb21lPTIpICU+JQogIG11dGF0ZSgKICAgIGluY29tZV9sZXZlbCA9IGNhc2Vfd2hlbigKICAgICAgICBtZWRpYW5faW5jb21lIDwgNTIxNjQgfiAibG93IiwKICAgICAgICBtZWRpYW5faW5jb21lID49IDUyMTY0IH4gImhpZ2giCiAgICAgICkKICApICU+JSAKICBmaWx0ZXIoaW5jb21lX2xldmVsID09ICJsb3ciKSAlPiUKICBzdF90cmFuc2Zvcm0oY3JzPTQyNjkpCiMgTG9hZCBhbmQgY2xlYW4gaGlnaCBpbmNvbWUgbmVpZ2hib3Job29kIHNoYXBlZmlsZQpoaWdoX2luY29tZSA8LSBzdF9yZWFkKCJpbmNvbWVfc2hhcGVmaWxlcy9tZWRpYW5faG91c2Vob2xkX2luY29tZS5zaHAiKSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUKICBzZWxlY3QoY3NhMjAxMCwgbWhoaTIwLCBnZW9tZXRyeSkgJT4lIAogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSAxLCBtZWRpYW5faW5jb21lPTIpICU+JQogIG11dGF0ZSgKICAgIGluY29tZV9sZXZlbCA9IGNhc2Vfd2hlbigKICAgICAgICBtZWRpYW5faW5jb21lIDwgNTIxNjQgfiAibG93IiwKICAgICAgICBtZWRpYW5faW5jb21lID49IDUyMTY0IH4gImhpZ2giCiAgICAgICkKICApICU+JSAKICBmaWx0ZXIoaW5jb21lX2xldmVsID09ICJoaWdoIikgJT4lCiAgc3RfdHJhbnNmb3JtKGNycz00MjY5KQojIHRhYmxlIGZvciBsZWFmbGV0CmJhbHRpbW9yZV9uZWlnaGJvcmhvb2RzX2luY29tZSA8LSBuZWlnaGJvcmhvb2RzICU+JSAKICBjbGVhbl9uYW1lcygpICU+JSAKICBzZWxlY3QoY3NhMjAxMCwgbWhoaTIwKSAlPiUgCiAgcmVuYW1lKG5laWdoYm9yaG9vZCA9IDEsIG1lZGlhbl9pbmNvbWU9MikgJT4lIAogIG11dGF0ZSgKICAgIGluY29tZV9sZXZlbCA9IGNhc2Vfd2hlbigKICAgICAgICBtZWRpYW5faW5jb21lIDwgNTIxNjQgfiAibG93IiwKICAgICAgICBtZWRpYW5faW5jb21lID49IDUyMTY0IH4gImhpZ2giCiAgICAgICkKICApCmBgYAoKI0hvdyBkb2VzIHRoZSBudW1iZXIgb2Ygc3VwZXJtYXJrZXRzIGNvbXBhcmUgaW4gbG93IGluY29tZSBhbmQgaGlnaCBpbmNvbWUgQmFsdGltb3JlIG5laWdoYm9yaG9vZHM/ClRoZXJlIGFyZSAyNSBzdXBlcm1hcmtldHMgaW4gbG93IGluY29tZSBuZWlnaGJvcmhvb2RzIGFuZCAyNCBzdXBlcm1hcmtldHMgaW4gaGlnaCBpbmNvbWUgbmVpZ2hib3Job29kcy4gV2hpbGUgbG93IGluY29tZSBuZWlnaGJvcmhvb2RzIGhhdmUgb25lIG1vcmUgc3VwZXJtYXJrZXQgdGhhbiBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzLCB0aGVyZSBhcmUgbW9yZSBsb3cgaW5jb21lIG5laWdoYm9yaG9vZHMgKDMyKSB0aGFuIGhpZ2ggaW5jb21lIG5laWdoYm9yaG9vZHMgKDIzKSwgbWFraW5nIHRoZSByYXRpbyBvZiBzdXBlcm1hcmtldHMgdG8gbmVpZ2hib3Job29kcyBncmVhdGVyIGZvciBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzLiBUaGVyZSBhcmUgc29tZSBsb3cgaW5jb21lIG5laWdoYm9yaG9vZHMgd2l0aG91dCBhIHN1cGVybWFya2V0IGF0IGFsbCwgd2hpbGUgdGhlcmUgYXJlIGVub3VnaCBzdXBlcm1hcmtldHMgZm9yIGV2ZXJ5IGhpZ2ggaW5jb21lIG5laWdoYm9yaG9vZCwgcGx1cyBhbiBhZGRpdGlvbmFsIG9uZS4gVGhpcyBzaG93cyB0aGF0IGhpZ2ggaW5jb21lIHJlc2lkZW50cyBoYXZlIGdyZWF0ZXIgYWNjZXNzIHRvIHN1cGVybWFya2V0cyBhbmQgZnJlc2ggZm9vZCB0aGFuIGxvdyBpbmNvbWUgcmVzaWRlbnRzLgoKYGBge3J9CiMgc29ydCBjb29yZGluYXRlcyBpbnRvIGxvdyBpbmNvbWUgbmVpZ2hib3Job29kcwpsb3dfaW5jb21lX3N1cGVybWFya2V0cyA8LSBzdXBlcm1hcmtldHMgJT4lCiAgc3Rfam9pbihsb3dfaW5jb21lKSAlPiUgCiAgZmlsdGVyKGluY29tZV9sZXZlbCA9PSAibG93IikKIyBzb3J0IGNvb3JkaW5hdGVzIGludG8gaGlnaCBpbmNvbWUgbmVpZ2hib3Job29kcwpoaWdoX2luY29tZV9zdXBlcm1hcmtldHMgPC0gc3VwZXJtYXJrZXRzICU+JQogIHN0X2pvaW4oaGlnaF9pbmNvbWUpICU+JSAKICBmaWx0ZXIoaW5jb21lX2xldmVsID09ICJoaWdoIikKYGBgCgojcGxvdCBzdXBlcm1hcmtldHMgaW4gYmFsdGltb3JlIGJhc2VkIG9uIGluY29tZQpgYGB7cn0KZ2dwbG90KCkrCmdlb21fc2YoZGF0YT1uZWlnaGJvcmhvb2RzKSsKZ2VvbV9zZihkYXRhPWxvd19pbmNvbWVfc3VwZXJtYXJrZXRzICU+JSBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSwgY3JzID0gNDMyNiksIG1hcHBpbmc9YWVzKGNvbG9yPWluY29tZV9sZXZlbCkpKwpnZW9tX3NmKGRhdGE9aGlnaF9pbmNvbWVfc3VwZXJtYXJrZXRzICU+JSBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSwgY3JzID0gNDMyNiksIG1hcHBpbmc9YWVzKGNvbG9yPWluY29tZV9sZXZlbCkpKwp0aGVtZV9taW5pbWFsKCkrCmxhYnModGl0bGUgPSAiU3VwZXJtYXJrZXRzIGluIEhpZ2ggYW5kIExvdyBJbmNvbWUgQmFsdGltb3JlIE5laWdoYm9yaG9vZHMiLCAKICAgICAgIHN1YnRpdGxlID0gIkpvaG5zIEhvcGtpbnMgYW5kIEJhbHRpbW9yZSBOZWlnaGJvcmhvb2QgSW5kaWNhdG9ycyBBbGxpYW5jZSBEYXRhLCAyMDIyIiwKICAgICAgIGNhcHRpb24gPSAiR3JhcGhpYyBieSBOYXRhbGllIEFkYW1zIikKYGBgCgojSG93IGRvZXMgdGhlIG51bWJlciBvZiBzbWFsbCBncm9jZXJ5IGFuZCBjb3JuZXIgc3RvcmVzIGNvbXBhcmUgaW4gbG93IGluY29tZSBhbmQgaGlnaCBpbmNvbWUgQmFsdGltb3JlIG5laWdoYm9yaG9vZHM/ClRoZXJlIGFyZSAyODkgc21hbGwgZ3JvY2VyeS9jb3JuZXIgc3RvcmVzIGluIGxvdyBpbmNvbWUgbmVpZ2hib3Job29kcyBhbmQgMTE1IHNtYWxsIGdyb2NlcnkvY29ybmVyIHN0b3JlcyBpbiBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzLiBMb3cgaW5jb21lIG5laWdoYm9yaG9vZHMgaGF2ZSBtb3JlIHRoYW4gdHdpY2UgYXMgbWFueSBzbWFsbCBncm9jZXJ5L2Nvcm5lciBzdG9yZXMgdGhhbiBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzIGFuZCBoYXZlIGEgZ3JlYXRlciByYXRpbyBvZiBzbWFsbCBncm9jZXJ5L2Nvcm5lciBzdG9yZXMgdGhhbiBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzLiBTbWFsbCBncm9jZXJ5L2Nvcm5lciBzdG9yZXMgdHlwaWNhbGx5IG9mZmVyIGV0aG5pYyBvciBjdWx0dXJhbCBmb29kIG9wdGlvbnMsIHN1Y2ggYXMgQXNpYW4gb3IgU291dGggQW1lcmljYW4uIFRoZSBwcmV2YWxlbmNlIG9mIHNtYWxsIGdyb2NlcnkvY29ybmVyIHN0b3JlcyBpbiBsb3cgaW5jb21lIG5laWdoYm9yaG9vZHMgaW5kaWNhdGVzIGEgcG9zc2libGUgaGlnaCBub24td2hpdGUgcG9wdWxhdGlvbiBpbiB0aG9zZSBuZWlnaGJvcmhvb2RzLiBTbWFsbCBncm9jZXJ5L2Nvcm5lciBzdG9yZXMgY291bGQgYWxzbyBtYWtlIHVwIGZvciB0aGUgYWJzZW5jZSBvZiBhY2Nlc3MgdG8gc3VwZXJtYXJrZXRzIGluIHRoZXNlIGNvbW11bml0aWVzLCBhbHRob3VnaCBhY2Nlc3MgdG8gZnJlc2ggZm9vZCBjb3VsZCBzdGlsbCBiZSBsaW1pdGVkLgoKYGBge3J9CiMgc29ydCBjb29yZGluYXRlcyBpbnRvIGxvdyBpbmNvbWUgbmVpZ2hib3Job29kcwpsb3dfaW5jb21lX3NtYWxsX2dyb2NlcnkgPC0gc21hbGxfZ3JvY2VyeSAlPiUKICBzdF9qb2luKGxvd19pbmNvbWUpICU+JSAKICBmaWx0ZXIoaW5jb21lX2xldmVsID09ICJsb3ciKQojIHNvcnQgY29vcmRpbmF0ZXMgaW50byBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzCmhpZ2hfaW5jb21lX3NtYWxsX2dyb2NlcnkgPC0gc21hbGxfZ3JvY2VyeSAlPiUKICBzdF9qb2luKGhpZ2hfaW5jb21lKSAlPiUgCiAgZmlsdGVyKGluY29tZV9sZXZlbCA9PSAiaGlnaCIpCmBgYAoKI3Bsb3Qgc21hbGwgZ3JvY2VyeSBzdG9yZXMgaW4gYmFsdGltb3JlIGJhc2VkIG9uIGluY29tZQpgYGB7cn0KZ2dwbG90KCkrCmdlb21fc2YoZGF0YT1uZWlnaGJvcmhvb2RzKSsKZ2VvbV9zZihkYXRhPWxvd19pbmNvbWVfc21hbGxfZ3JvY2VyeSAlPiUgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQzMjYpLCBtYXBwaW5nPWFlcyhjb2xvcj1pbmNvbWVfbGV2ZWwpKSsKZ2VvbV9zZihkYXRhPWhpZ2hfaW5jb21lX3NtYWxsX2dyb2NlcnkgJT4lIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpLCBjcnMgPSA0MzI2KSwgbWFwcGluZz1hZXMoY29sb3I9aW5jb21lX2xldmVsKSkrCnRoZW1lX21pbmltYWwoKSsKbGFicyh0aXRsZSA9ICJTbWFsbCBHcm9jZXJ5IGFuZCBDb3JuZXIgU3RvcmVzIGluIEhpZ2ggYW5kIExvdyBJbmNvbWUgQmFsdGltb3JlIE5laWdoYm9yaG9vZHMiLCAKICAgICAgIHN1YnRpdGxlID0gIkpvaG5zIEhvcGtpbnMgYW5kIEJhbHRpbW9yZSBOZWlnaGJvcmhvb2QgSW5kaWNhdG9ycyBBbGxpYW5jZSBEYXRhLCAyMDIyIiwKICAgICAgIGNhcHRpb24gPSAiR3JhcGhpYyBieSBOYXRhbGllIEFkYW1zIikKYGBgCgojSG93IGRvZXMgdGhlIG51bWJlciBvZiBjb252ZW5pZW5jZSBzdG9yZXMgY29tcGFyZSBpbiBsb3cgaW5jb21lIGFuZCBoaWdoIGluY29tZSBCYWx0aW1vcmUgbmVpZ2hib3Job29kcz8KVGhlcmUgYXJlIDE2NiBjb252ZW5pZW5jZSBzdG9yZXMgaW4gbG93IGluY29tZSBuZWlnaGJvcmhvb2RzIGFuZCAxMTYgY29udmVuaWVuY2Ugc3RvcmVzIGluIGhpZ2ggaW5jb21lIG5laWdoYm9yaG9vZHMuIFRoZSBhdmVyYWdlIG51bWJlciBvZiBjb252ZW5pZW5jZSBzdG9yZXMgaW4gbG93IGFuZCBoaWdoIGluY29tZSBuZWlnaGJvcmhvb2RzIGlzIHZpcnR1YWxseSB0aGUgc2FtZSAoNS4xIGluIGxvdyBpbmNvbWUgY29tcGFyZWQgdG8gNS4wIGluIGhpZ2ggaW5jb21lKS4gIENvbnZlbmllbmNlIHN0b3JlcyB0eXBpY2FsbHkgaGF2ZSAianVuayBmb29kIiBhbmQgc25hY2tzLCBsaWtlIGNoaXBzLCBzb2RhIGFuZCBjYW5keS4gTGFyZ2UgY2hhaW4gY29udmVuaWVuY2Ugc3RvcmVzLCBzdWNoIGFzIFJveWFsIEZhcm1zIGFuZCBXYXdhLCBoYXZlIG9wdGlvbnMgdG8gb3JkZXIgaG90IGZvb2QsIGxpa2UgZnJpZWQgY2hpY2tlbiBhbmQgc2FuZHdpY2hlcy4gU29tZSBjb252ZW5pZW5jZSBzdG9yZXMgaGF2ZSBmcmVzaCBmcnVpdCwgc3VjaCBhcyBhcHBsZXMgYW5kIGJhbmFuYXMsIGJ1dCBvdmVyYWxsLCBkbyBub3Qgb2ZmZXIgZ3JlYXQgYWNjZXNzIHRvIGZyZXNoIGZvb2QuIFdoaWxlIHRoZXJlIGlzIGFuIGVxdWFsIHBlcmNlbnRhZ2Ugb2YgY29udmVuaWVuY2Ugc3RvcmVzIGluIGhpZ2ggaW5jb21lIGFuZCBsb3cgaW5jb21lIG5laWdoYm9yaG9vZHMsIHRoZSBsb3dlciBwZXJjZW50YWdlIG9mIHN1cGVybWFya2V0cyBpbiBsb3cgaW5jb21lIG5laWdoYm9yaG9vZHMgY291bGQgaW5kaWNhdGUgYSBzdHJvbmdlciByZWxpYW5jZSBvbiBjb252ZW5pZW5jZSBzdG9yZXMgZm9yIGJ1eWluZyBmb29kLgoKYGBge3J9CiMgc29ydCBjb29yZGluYXRlcyBpbnRvIGxvdyBpbmNvbWUgbmVpZ2hib3Job29kcwpsb3dfaW5jb21lX2NvbnZlbmllbmNlX3N0b3JlcyA8LSBjb252ZW5pZW5jZV9zdG9yZXMgJT4lCiAgc3Rfam9pbihsb3dfaW5jb21lKSAlPiUgCiAgZmlsdGVyKGluY29tZV9sZXZlbCA9PSAibG93IikKIyBzb3J0IGNvb3JkaW5hdGVzIGludG8gaGlnaCBpbmNvbWUgbmVpZ2hib3Job29kcwpoaWdoX2luY29tZV9jb252ZW5pZW5jZV9zdG9yZXMgPC0gY29udmVuaWVuY2Vfc3RvcmVzICU+JQogIHN0X2pvaW4oaGlnaF9pbmNvbWUpICU+JSAKICBmaWx0ZXIoaW5jb21lX2xldmVsID09ICJoaWdoIikKYGBgCgojcGxvdCBjb252ZW5pZW5jZSBzdG9yZXMgaW4gYmFsdGltb3JlIGJhc2VkIG9uIGluY29tZQpgYGB7cn0KZ2dwbG90KCkrCmdlb21fc2YoZGF0YT1uZWlnaGJvcmhvb2RzKSsKZ2VvbV9zZihkYXRhPWxvd19pbmNvbWVfY29udmVuaWVuY2Vfc3RvcmVzICU+JSBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSwgY3JzID0gNDMyNiksIG1hcHBpbmc9YWVzKGNvbG9yPWluY29tZV9sZXZlbCkpKwpnZW9tX3NmKGRhdGE9aGlnaF9pbmNvbWVfY29udmVuaWVuY2Vfc3RvcmVzICU+JSBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSwgY3JzID0gNDMyNiksIG1hcHBpbmc9YWVzKGNvbG9yPWluY29tZV9sZXZlbCkpKwp0aGVtZV9taW5pbWFsKCkrCmxhYnModGl0bGUgPSAiQ29udmVuaWVuY2UgU3RvcmVzIGluIEhpZ2ggYW5kIExvdyBJbmNvbWUgQmFsdGltb3JlIE5laWdoYm9yaG9vZHMiLCAKICAgICAgIHN1YnRpdGxlID0gIkpvaG5zIEhvcGtpbnMgYW5kIEJhbHRpbW9yZSBOZWlnaGJvcmhvb2QgSW5kaWNhdG9ycyBBbGxpYW5jZSBEYXRhLCAyMDIyIiwKICAgICAgIGNhcHRpb24gPSAiR3JhcGhpYyBieSBOYXRhbGllIEFkYW1zIikKYGBgCgojSW5jb21lIExlYWZsZXQgR3JhcGgKYGBge3J9CnBhbCA8LSBjb2xvckZhY3RvcigKICBwYWxldHRlID0gYygncmVkJywgJ2RhcmtncmVlbicsICdibGFjaycpLAogIGRvbWFpbiA9IGJhbHRpbW9yZV9zdG9yZXMkc3RvcmVfdHlwZSkKCnBhbDIgPC0gY29sb3JGYWN0b3IoCiAgcGFsZXR0ZSA9IGMoJyNmYmQwMDknLCAnIzE5OWJkNicpLAogIGRvbWFpbiA9IGJhbHRpbW9yZV9uZWlnaGJvcmhvb2RzX2luY29tZSRpbmNvbWVfbGV2ZWwpCgpsZWFmbGV0KCkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgYWRkUG9seWdvbnMoZGF0YT1sb3dfaW5jb21lLAogICAgICAgICAgICAgIGNvbG9yID0gKCIjMTk5YmQ2IiksCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMS41LAogICAgICAgICAgICAgIHNtb290aEZhY3RvciA9IDAuMiwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgICBsYWJlbCA9IGxvd19pbmNvbWUkbmVpZ2hib3Job29kKSAlPiUgCiAgYWRkUG9seWdvbnMoZGF0YT1oaWdoX2luY29tZSwKICAgICAgICAgICAgICBjb2xvciA9ICgiI2ZiZDAwOSIpLAogICAgICAgICAgICAgIHdlaWdodCA9IDEuNSwKICAgICAgICAgICAgICBzbW9vdGhGYWN0b3IgPSAwLjIsCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjEsCiAgICAgICAgICAgICAgbGFiZWwgPSBoaWdoX2luY29tZSRuZWlnaGJvcmhvb2QpICU+JQogIGFkZENpcmNsZXMoZGF0YT1iYWx0aW1vcmVfc3RvcmVzLAogICAgICAgICAgICAgd2VpZ2h0ID0gMiwKICAgICAgICAgICAgIGNvbG9yID0gfnBhbChzdG9yZV90eXBlKSwKICAgICAgICAgICAgIGxhYmVsPSBwYXN0ZSgiU3RvcmUgTmFtZToiLGJhbHRpbW9yZV9zdG9yZXMkbmFtZSkpICU+JSAKICAgIGFkZExlZ2VuZCgKICAgcG9zaXRpb24gPSAiYm90dG9tbGVmdCIsCiAgICBwYWwgPSBwYWwsCiAgICB2YWx1ZXMgPSBiYWx0aW1vcmVfc3RvcmVzJHN0b3JlX3R5cGUsCiAgICB0aXRsZSA9ICJTdG9yZXMgYnkgVHlwZSIsIGdyb3VwPSJncm91cF8xIikgJT4lIAogIGFkZExlZ2VuZCgKICAgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLAogICAgcGFsID0gcGFsMiwKICAgIHZhbHVlcyA9IGJhbHRpbW9yZV9uZWlnaGJvcmhvb2RzX2luY29tZSRpbmNvbWVfbGV2ZWwsCiAgICB0aXRsZSA9ICJOZWlnaGJvcmhvb2QgSW5jb21lIiwgZ3JvdXA9Imdyb3VwXzIiKSAlPiUgCiAgYWRkTGF5ZXJzQ29udHJvbChvdmVybGF5R3JvdXBzID0gYygiZ3JvdXBfMSIsImdyb3VwXzIiKSwKICAgICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBGQUxTRSkpCgpgYGAKCiNjbGVhbiByYWNlIGRhdGEgYW5kIG5laWdoYm9yaG9vZHMgc2hhcGVmaWxlClNlbGVjdGVkIHdoaXRlIGRhdGEgYW5kIGNsZWFuZWQgY29sdW1uIG5hbWVzLgoKV2UgZGVmaW5lZCBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzIGFzIG5laWdoYm9yaG9vZHMgd2l0aCBhIG5laWdoYm9yaG9vZCB3aXRoIGEgNTAlIG9yIGdyYXRlciB3aGl0ZSBwb3B1bGF0aW9uIGFuZCBub24gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcyBhcyBhIG5laWdoYm9yaG9vZCB3aXRoIGEgbGVzcyB0aGFuIDUwJSB3aGl0ZSBwb3B1bGF0aW9uLiBUaGVyZSBhcmUgMTEgbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcyBhbmQgNDQgbm9uIG1ham9yaXR5IHdoaXRlIG5laWdoYm9yaG9vZHMuCgpgYGB7cn0KIyBmaWx0ZXIgZm9yIG1ham9yaXR5IHdoaXRlIG5laWdoYm9yaG9vZHMKbWFqb3JpdHlfd2hpdGUgPC0gc3RfcmVhZCgiaW5jb21lX3NoYXBlZmlsZXMvbWVkaWFuX2hvdXNlaG9sZF9pbmNvbWUuc2hwIikgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lCiAgc2VsZWN0KGNzYTIwMTAsIGdlb21ldHJ5KSAlPiUgCiAgcmVuYW1lKG5laWdoYm9yaG9vZCA9IDEpICU+JSAKICBpbm5lcl9qb2luKHBlcmNlbnRfd2hpdGUyLCBieT0ibmVpZ2hib3Job29kIikgJT4lIAogIG11dGF0ZSgKICAgIHBvcHVsYXRpb25fc3RhdHVzID0gY2FzZV93aGVuKAogICAgICAgIHBlcmNlbnRfd2hpdGUgPCA1MCB+ICJub25fbWFqb3JpdHlfd2hpdGUiLAogICAgICAgIHBlcmNlbnRfd2hpdGUgPj0gNTAgfiAibWFqb3JpdHlfd2hpdGUiCiAgICAgICkKICApICU+JQogIGZpbHRlcihwb3B1bGF0aW9uX3N0YXR1cyA9PSAibWFqb3JpdHlfd2hpdGUiKSAlPiUKICBzdF90cmFuc2Zvcm0oY3JzPTQyNjkpCiMgZmlsdGVyIGZvciBub24gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcwpub25fbWFqb3JpdHlfd2hpdGUgPC0gc3RfcmVhZCgiaW5jb21lX3NoYXBlZmlsZXMvbWVkaWFuX2hvdXNlaG9sZF9pbmNvbWUuc2hwIikgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lCiAgc2VsZWN0KGNzYTIwMTAsIGdlb21ldHJ5KSAlPiUgCiAgcmVuYW1lKG5laWdoYm9yaG9vZCA9IDEpICU+JSAKICBpbm5lcl9qb2luKHBlcmNlbnRfd2hpdGUyLCBieT0ibmVpZ2hib3Job29kIikgJT4lIAogIG11dGF0ZSgKICAgIHBvcHVsYXRpb25fc3RhdHVzID0gY2FzZV93aGVuKAogICAgICAgIHBlcmNlbnRfd2hpdGUgPCA1MCB+ICJub25fbWFqb3JpdHlfd2hpdGUiLAogICAgICAgIHBlcmNlbnRfd2hpdGUgPj0gNTAgfiAibWFqb3JpdHlfd2hpdGUiCiAgICAgICkKICApICU+JQogIGZpbHRlcihwb3B1bGF0aW9uX3N0YXR1cyA9PSAibm9uX21ham9yaXR5X3doaXRlIikgJT4lCiAgc3RfdHJhbnNmb3JtKGNycz00MjY5KQojIHRhYmxlIGZvciBsZWFmbGV0CmJhbHRpbW9yZV9uZWlnaGJvcmhvb2RzX3JhY2UgPC0gYmFsdGltb3JlX3BvcHVsYXRpb24gJT4lIAogIHNlbGVjdChuZWlnaGJvcmhvb2QsIHBlcmNlbnRfd2hpdGUpICU+JQogIG11dGF0ZSgKICAgIHBvcHVsYXRpb25fc3RhdHVzID0gY2FzZV93aGVuKAogICAgICAgIHBlcmNlbnRfd2hpdGUgPCA1MCB+ICJub25fbWFqb3JpdHlfd2hpdGUiLAogICAgICAgIHBlcmNlbnRfd2hpdGUgPj0gNTAgfiAibWFqb3JpdHlfd2hpdGUiCiAgICAgICkKICApCmBgYAoKI0hvdyBkb2VzIHRoZSBudW1iZXIgb2Ygc3VwZXJtYXJrZXRzIGNvbXBhcmUgaW4gbWFqb3JpdHkgd2hpdGUgYW5kIG5vbiBtYWpvcml0eSB3aGl0ZSBCYWx0aW1vcmUgbmVpZ2hib3Job29kcz8KVGhlcmUgYXJlIDE0IHN1cGVybWFya2V0cyBpbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzIGFuZCAzNSBzdXBlcm1hcmtldHMgaW4gbm9uIG1ham9yaXR5IHdoaXRlIG5laWdoYm9yaG9vZHMuIFdoaWxlIG5vbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzIGhhdmUgYSBoaWdoZXIgbnVtYmVyIG9mIHN1cGVybWFya2V0cyB0aGUgcmF0aW8gb2Ygc3VwZXJtYXJrZXRzIGZvciBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzICgxNCBzdXBlcm1hcmtldHMgZm9yIDExIG5laWdoYm9yaG9vZHMpIGlzIGdyZWF0ZXIgdGhhbiB0aGUgcmF0aW8gb2Ygc3VwZXJtYXJrZXRzIGZvciBub24gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcyAoMzUgc3VwZXJtYXJrZXRzIGZvciA0NCBuZWlnaGJvcmhvb2RzKS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB3aGl0ZSByZXNpZGVudHMgaGF2ZSBncmVhdGVyIGFjY2VzcyB0byBzdXBlcm1hcmtldHMgYW5kIGZyZXNoIGZvb2QgdGhhbiBub24gd2hpdGUgcmVzaWRlbnRzLgoKYGBge3J9CiMgc29ydCBjb29yZGluYXRlcyBpbnRvIG1ham9yaXR5IHdoaXRlIG5laWdoYm9yaG9vZHMKbWFqb3JpdHlfd2hpdGVfc3VwZXJtYXJrZXRzIDwtIHN1cGVybWFya2V0cyAlPiUKICBzdF9qb2luKG1ham9yaXR5X3doaXRlKSAlPiUgCiAgZmlsdGVyKHBvcHVsYXRpb25fc3RhdHVzID09ICJtYWpvcml0eV93aGl0ZSIpCiMgc29ydCBjb29yZGluYXRlcyBpbnRvIG5vbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzCm5vbl9tYWpvcml0eV93aGl0ZV9zdXBlcm1hcmtldHMgPC0gc3VwZXJtYXJrZXRzICU+JQogIHN0X2pvaW4obm9uX21ham9yaXR5X3doaXRlKSAlPiUgCiAgZmlsdGVyKHBvcHVsYXRpb25fc3RhdHVzID09ICJub25fbWFqb3JpdHlfd2hpdGUiKQpgYGAKCiNwbG90IHN1cGVybWFya2V0cyBpbiBiYWx0aW1vcmUgYmFzZWQgb24gcmFjZQpgYGB7cn0KZ2dwbG90KCkrCmdlb21fc2YoZGF0YT1uZWlnaGJvcmhvb2RzKSsKZ2VvbV9zZihkYXRhPW1ham9yaXR5X3doaXRlX3N1cGVybWFya2V0cyAlPiUgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQzMjYpLCBtYXBwaW5nPWFlcyhjb2xvcj1wb3B1bGF0aW9uX3N0YXR1cykpKwpnZW9tX3NmKGRhdGE9bm9uX21ham9yaXR5X3doaXRlX3N1cGVybWFya2V0cyAlPiUgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQzMjYpLCBtYXBwaW5nPWFlcyhjb2xvcj1wb3B1bGF0aW9uX3N0YXR1cykpKwp0aGVtZV9taW5pbWFsKCkrCmxhYnModGl0bGUgPSAiU3VwZXJtYXJrZXRzIGluIE1ham9yaXR5IFdoaXRlIGFuZCBOb24gTWFqb3JpdHkgV2hpdGUgQmFsdGltb3JlIE5laWdoYm9yaG9vZHMiLCAKICAgICAgIHN1YnRpdGxlID0gIkpvaG5zIEhvcGtpbnMgYW5kIEJhbHRpbW9yZSBOZWlnaGJvcmhvb2QgSW5kaWNhdG9ycyBBbGxpYW5jZSBEYXRhLCAyMDIyIiwKICAgICAgIGNhcHRpb24gPSAiR3JhcGhpYyBieSBOYXRhbGllIEFkYW1zIikKYGBgCgojSG93IGRvZXMgdGhlIG51bWJlciBvZiBzbWFsbCBncm9jZXJ5IGFuZCBjb3JuZXIgc3RvcmVzIGNvbXBhcmUgaW4gbWFqb3JpdHkgd2hpdGUgYW5kIG5vbiBtYWpvcml0eSB3aGl0ZSBCYWx0aW1vcmUgbmVpZ2hib3Job29kcz8KVGhlcmUgYXJlIDEyIHRpbWVzIGFzIG1hbnkgc21hbGwgZ3JvY2VyeS9jb3JuZXIgc3RvcmVzIGluIG5vbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzICgzNzMpIHRoYW4gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcyAoMzEpLiBTbWFsbCBncm9jZXJ5L2Nvcm5lciBzdG9yZXMgdHlwaWNhbGx5IG9mZmVyIGV0aG5pYyBvciBjdWx0dXJhbCBmb29kIG9wdGlvbnMsIHN1Y2ggYXMgQXNpYW4gb3IgU291dGggQW1lcmljYW4sIHNvIGl0IG1ha2VzIHNlbnNlIGZvciBtb3N0IG9mIHRoZXNlIHN0b3JlcyB0byBiZSBpbiBtYWpvcml0eSBub24gd2hpdGUgY29tbXVuaXRpZXMuIEl0IGlzIHVuY2xlYXIgZnJvbSB0aGlzIGRhdGEgd2hldGhlciB0aGUgaGlnaCBudW1iZXIgb2Ygc21hbGwgZ3JvY2VyeS9jb3JuZXIgc3RvcmVzIGlzIGR1ZSB0byBwcmVmZXJlbmNlIG9mIHRoZSBuZWlnaGJvcmhvb2QgcG9wdWxhdGlvbnMsIGEgbGFjayBvZiBhY2Nlc3MgdG8gb3RoZXIgdHlwZXMgb2YgZm9vZCBzdG9yZXMgKHN1Y2ggYXMgc3VwZXJtYXJrZXRzKSwgb3RoZXIgZmFjdG9ycyBvciBhIGNvbWJpbmF0aW9uIG9mIGZhY3RvcnMuCgpgYGB7cn0KIyBzb3J0IGNvb3JkaW5hdGVzIGludG8gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcwptYWpvcml0eV93aGl0ZV9zbWFsbF9ncm9jZXJ5IDwtIHNtYWxsX2dyb2NlcnkgJT4lCiAgc3Rfam9pbihtYWpvcml0eV93aGl0ZSkgJT4lIAogIGZpbHRlcihwb3B1bGF0aW9uX3N0YXR1cyA9PSAibWFqb3JpdHlfd2hpdGUiKQojIHNvcnQgY29vcmRpbmF0ZXMgaW50byBub24gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcwpub25fbWFqb3JpdHlfd2hpdGVfc21hbGxfZ3JvY2VyeSA8LSBzbWFsbF9ncm9jZXJ5ICU+JQogIHN0X2pvaW4obm9uX21ham9yaXR5X3doaXRlKSAlPiUgCiAgZmlsdGVyKHBvcHVsYXRpb25fc3RhdHVzID09ICJub25fbWFqb3JpdHlfd2hpdGUiKQpgYGAKCiNwbG90IHNtYWxsIGdyb2Nlcnkgc3RvcmVzIGluIGJhbHRpbW9yZSBiYXNlZCBvbiByYWNlCmBgYHtyfQpnZ3Bsb3QoKSsKZ2VvbV9zZihkYXRhPW5laWdoYm9yaG9vZHMpKwpnZW9tX3NmKGRhdGE9bWFqb3JpdHlfd2hpdGVfc21hbGxfZ3JvY2VyeSAlPiUgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQzMjYpLCBtYXBwaW5nPWFlcyhjb2xvcj1wb3B1bGF0aW9uX3N0YXR1cykpKwpnZW9tX3NmKGRhdGE9bm9uX21ham9yaXR5X3doaXRlX3NtYWxsX2dyb2NlcnkgJT4lIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpLCBjcnMgPSA0MzI2KSwgbWFwcGluZz1hZXMoY29sb3I9cG9wdWxhdGlvbl9zdGF0dXMpKSsKdGhlbWVfbWluaW1hbCgpKwpsYWJzKHRpdGxlID0gIlNtYWxsIEdyb2NlcnkgYW5kIENvcm5lciBTdG9yZXMgaW4gTWFqb3JpdHkgV2hpdGUgYW5kIE5vbiBNYWpvcml0eSBXaGl0ZSBCYWx0aW1vcmUgTmVpZ2hib3Job29kcyIsIAogICAgICAgc3VidGl0bGUgPSAiSm9obnMgSG9wa2lucyBhbmQgQmFsdGltb3JlIE5laWdoYm9yaG9vZCBJbmRpY2F0b3JzIEFsbGlhbmNlIERhdGEsIDIwMjIiLAogICAgICAgY2FwdGlvbiA9ICJHcmFwaGljIGJ5IE5hdGFsaWUgQWRhbXMiKQpgYGAKCiNIb3cgZG9lcyB0aGUgbnVtYmVyIG9mIGNvbnZlbmllbmNlIHN0b3JlcyBjb21wYXJlIGluIG1ham9yaXR5IHdoaXRlIGFuZCBub24gbWFqb3JpdHkgd2hpdGUgQmFsdGltb3JlIG5laWdoYm9yaG9vZHM/ClRoZXJlIGFyZSA0OSBjb252ZW5pZW5jZSBzdG9yZXMgaW4gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcyBhbmQgMjMzIGNvbnZlbmllbmNlIHN0b3JlcyBpbiBub24gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcy4gVGhlIHBlcmNlbnRhZ2Ugb2YgY29udmVuaWVuY2Ugc3RvcmVzIGluIG1ham9yaXR5IHdoaXRlIGFuZCBub24gbWFqb3JpdHkgd2hpdGUgbmVpZ2hib3Job29kcyBpcyBuZWFybHkgZXF1YWwgKDQuNSBpbiBtYWpvcml0eSB3aGl0ZSBjb21wYXJlZCB0byA1LjMgaW4gbm9uIG1ham9yaXR5IHdoaXRlKS4gQ29udmVuaWVuY2Ugc3RvcmVzIHR5cGljYWxseSBoYXZlICJqdW5rIGZvb2QiIGFuZCBzbmFja3MsIGxpa2UgY2hpcHMsIHNvZGEgYW5kIGNhbmR5LiBMYXJnZSBjaGFpbiBjb252ZW5pZW5jZSBzdG9yZXMsIHN1Y2ggYXMgUm95YWwgRmFybXMgYW5kIFdhd2EsIGhhdmUgb3B0aW9ucyB0byBvcmRlciBob3QgZm9vZCwgbGlrZSBmcmllZCBjaGlja2VuIGFuZCBzYW5kd2ljaGVzLiBTb21lIGNvbnZlbmllbmNlIHN0b3JlcyBoYXZlIGZyZXNoIGZydWl0LCBzdWNoIGFzIGFwcGxlcyBhbmQgYmFuYW5hcywgYnV0IG92ZXJhbGwsIGRvIG5vdCBvZmZlciBncmVhdCBhY2Nlc3MgdG8gZnJlc2ggZm9vZC4gV2hpbGUgdGhlcmUgaXMgYSBuZWFybHkgZXF1YWwgcGVyY2VudGFnZSBvZiBjb252ZW5pZW5jZSBzdG9yZXMgaW4gbWFqb3JpdHkgd2hpdGUgYW5kIG5vbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzLCB0aGUgbG93ZXIgcGVyY2VudGFnZSBvZiBzdXBlcm1hcmtldHMgaW4gbm9uIG1ham9yaXR5IHdoaXRlIG5laWdoYm9yaG9vZHMgY291bGQgaW5kaWNhdGUgYSBzdHJvbmdlciByZWxpYW5jZSBvbiBjb252ZW5pZW5jZSBzdG9yZXMgZm9yIGJ1eWluZyBmb29kLgoKYGBge3J9CiMgc29ydCBjb29yZGluYXRlcyBpbnRvIG1ham9yaXR5IHdoaXRlIG5laWdoYm9yaG9vZHMKbWFqb3JpdHlfd2hpdGVfY29udmVuaWVuY2Vfc3RvcmVzIDwtIGNvbnZlbmllbmNlX3N0b3JlcyAlPiUKICBzdF9qb2luKG1ham9yaXR5X3doaXRlKSAlPiUgCiAgZmlsdGVyKHBvcHVsYXRpb25fc3RhdHVzID09ICJtYWpvcml0eV93aGl0ZSIpCiMgc29ydCBjb29yZGluYXRlcyBpbnRvIG5vbiBtYWpvcml0eSB3aGl0ZSBuZWlnaGJvcmhvb2RzCm5vbl9tYWpvcml0eV93aGl0ZV9jb252ZW5pZW5jZV9zdG9yZXMgPC0gY29udmVuaWVuY2Vfc3RvcmVzICU+JQogIHN0X2pvaW4obm9uX21ham9yaXR5X3doaXRlKSAlPiUgCiAgZmlsdGVyKHBvcHVsYXRpb25fc3RhdHVzID09ICJub25fbWFqb3JpdHlfd2hpdGUiKQpgYGAKCiNwbG90IGNvbnZlbmllbmNlIHN0b3JlcyBpbiBiYWx0aW1vcmUgYmFzZWQgb24gcmFjZQpgYGB7cn0KZ2dwbG90KCkrCmdlb21fc2YoZGF0YT1uZWlnaGJvcmhvb2RzKSsKZ2VvbV9zZihkYXRhPW1ham9yaXR5X3doaXRlX2NvbnZlbmllbmNlX3N0b3JlcyAlPiUgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQzMjYpLCBtYXBwaW5nPWFlcyhjb2xvcj1wb3B1bGF0aW9uX3N0YXR1cykpKwpnZW9tX3NmKGRhdGE9bm9uX21ham9yaXR5X3doaXRlX2NvbnZlbmllbmNlX3N0b3JlcyAlPiUgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IiksIGNycyA9IDQzMjYpLCBtYXBwaW5nPWFlcyhjb2xvcj1wb3B1bGF0aW9uX3N0YXR1cykpKwp0aGVtZV9taW5pbWFsKCkrCmxhYnModGl0bGUgPSAiQ29udmVuaWVuY2UgU3RvcmVzIGluIE1ham9yaXR5IFdoaXRlIGFuZCBOb24gTWFqb3JpdHkgV2hpdGUgQmFsdGltb3JlIE5laWdoYm9yaG9vZHMiLCAKICAgICAgIHN1YnRpdGxlID0gIkpvaG5zIEhvcGtpbnMgYW5kIEJhbHRpbW9yZSBOZWlnaGJvcmhvb2QgSW5kaWNhdG9ycyBBbGxpYW5jZSBEYXRhLCAyMDIyIiwKICAgICAgIGNhcHRpb24gPSAiR3JhcGhpYyBieSBOYXRhbGllIEFkYW1zIikKYGBgCgojbGVhZmxldCByYWNlIGdyYXBoCmBgYHtyfQpwYWwxIDwtIGNvbG9yRmFjdG9yKAogIHBhbGV0dGUgPSBjKCdyZWQnLCAnZGFya2dyZWVuJywgJ2JsYWNrJyksCiAgZG9tYWluID0gYmFsdGltb3JlX3N0b3JlcyRzdG9yZV90eXBlKQoKcGFsMiA8LSBjb2xvckZhY3RvcigKICBwYWxldHRlID0gYygnI2ZiZDAwOScsICcjMTk5YmQ2JyksCiAgZG9tYWluID0gYmFsdGltb3JlX25laWdoYm9yaG9vZHNfcmFjZSRwb3B1bGF0aW9uX3N0YXR1cykKCmxlYWZsZXQoKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhPW1ham9yaXR5X3doaXRlLAogICAgICAgICAgICAgIGNvbG9yID0gKCIjZmJkMDA5IiksCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMS41LAogICAgICAgICAgICAgIHNtb290aEZhY3RvciA9IDAuMiwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgICBsYWJlbCA9IG1ham9yaXR5X3doaXRlJG5laWdoYm9yaG9vZCkgJT4lIAogIGFkZFBvbHlnb25zKGRhdGE9bm9uX21ham9yaXR5X3doaXRlLAogICAgICAgICAgICAgIGNvbG9yID0gKCIjMTk5YmQ2IiksCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMS41LAogICAgICAgICAgICAgIHNtb290aEZhY3RvciA9IDAuMiwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgICBsYWJlbCA9IG5vbl9tYWpvcml0eV93aGl0ZSRuZWlnaGJvcmhvb2QpICU+JQogIGFkZENpcmNsZXMoZGF0YT1iYWx0aW1vcmVfc3RvcmVzLAogICAgICAgICAgICAgd2VpZ2h0ID0gMiwKICAgICAgICAgICAgIGNvbG9yID0gfnBhbChzdG9yZV90eXBlKSwKICAgICAgICAgICAgIGxhYmVsPSBwYXN0ZSgiU3RvcmUgTmFtZToiLGJhbHRpbW9yZV9zdG9yZXMkbmFtZSkpICU+JSAKICAgIGFkZExlZ2VuZCgKICAgcG9zaXRpb24gPSAiYm90dG9tbGVmdCIsCiAgICBwYWwgPSBwYWwxLAogICAgdmFsdWVzID0gYmFsdGltb3JlX3N0b3JlcyRzdG9yZV90eXBlLAogICAgdGl0bGUgPSAiU3RvcmVzIGJ5IFR5cGUiLCBncm91cD0iZ3JvdXBfMSIpICU+JSAKICBhZGRMZWdlbmQoCiAgIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IiwKICAgIHBhbCA9IHBhbDIsCiAgICB2YWx1ZXMgPSBiYWx0aW1vcmVfbmVpZ2hib3Job29kc19yYWNlJHBvcHVsYXRpb25fc3RhdHVzLAogICAgdGl0bGUgPSAiTmVpZ2hib3Job29kIFJhY2UiLCBncm91cD0iZ3JvdXBfMiIpICU+JSAKICBhZGRMYXllcnNDb250cm9sKG92ZXJsYXlHcm91cHMgPSBjKCJncm91cF8xIiwiZ3JvdXBfMiIpLAogICAgICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKSkKCgpgYGAKCgoK